﻿using Microsoft.Extensions.DependencyInjection;
using System.Reflection;

namespace Service.Framework;

public static class DynamicInject
{

    public static IEnumerable<Assembly> _loadedAssemblies = new List<Assembly>();

    public static void AddServicesOfType<T>(this IServiceCollection serviceCollection, params string[] scanAssembliesStartsWith)
    {

        if (serviceCollection == null)
        {
            throw new ArgumentNullException("serviceCollection");
        }
        ServiceLifetime serviceLifetime = ServiceLifetime.Scoped;
        serviceLifetime = typeof(T).Name switch
        {
            "ITransientService" => ServiceLifetime.Transient,
            "IScopedService" => ServiceLifetime.Scoped,
            "ISingletonService" => ServiceLifetime.Singleton,
            _ => throw new ArgumentException("这个类型" + typeof(T).Name + " 在这个上下文中是非法的"),
        };
        if (!_loadedAssemblies.Any())
        {
            LoadAssemblies(scanAssembliesStartsWith);
        }


        //ServiceCollectionExtensions.Scan(serviceCollection, delegate (ITypeSourceSelector w)
        //{
        //    w.FromAssemblies(_loadedAssemblies)
        //    .AddClasses(delegate (IImplementationTypeFilter classes)
        //    {
        //        classes.AssignableTo(typeof(IScopedService));
        //    }).UsingRegistrationStrategy(RegistrationStrategy.Skip).AsImplementedInterfaces().WithScopedLifetime()
        //    .AddClasses(delegate (IImplementationTypeFilter classes)
        //    {
        //        classes.AssignableTo(typeof(ISingletonService));
        //    }).UsingRegistrationStrategy(RegistrationStrategy.Skip).AsImplementedInterfaces().WithSingletonLifetime()
        //    .AddClasses(delegate (IImplementationTypeFilter classes)
        //    {
        //        classes.AssignableTo(typeof(ITransientService));
        //    }).UsingRegistrationStrategy(RegistrationStrategy.Skip).AsImplementedInterfaces().WithTransientLifetime();
        //});


        List<Type> list = (from type in _loadedAssemblies.SelectMany((Assembly assembly) => assembly.GetTypes())
                           where typeof(T).IsAssignableFrom(type) && type.IsClass
                           select type).ToList();
        foreach (Type implementation in list)
        {
            Type[] array = (from i in implementation.GetInterfaces()
                            where i != typeof(ITransientService) && i != typeof(IScopedService) && i != typeof(ISingletonService)
                            select i).ToArray();
            if (array.Any())
            {
                Type[] array2 = array;
                foreach (Type type2 in array2)
                {
                    bool flag = implementation.IsGenericType && implementation.IsGenericTypeDefinition;
                    Type service = ((flag && type2.IsGenericType && !type2.IsGenericTypeDefinition && type2.ContainsGenericParameters) ? type2.GetGenericTypeDefinition() : type2);
                    if (!serviceCollection.Any((ServiceDescriptor s) => s.ServiceType == service && s.ImplementationType == implementation))
                    {
                        serviceCollection.Add(new ServiceDescriptor(service, implementation, serviceLifetime));
                    }
                }
            }
            else if (implementation.IsClass && !serviceCollection.Any((ServiceDescriptor s) => s.ServiceType == implementation && s.ImplementationType == implementation))
            {
                serviceCollection.Add(new ServiceDescriptor(implementation, implementation, serviceLifetime));
            }
        }
    }

    public static void AddServicesWithAttributeOfType<T>(this IServiceCollection serviceCollection, params string[] scanAssembliesStartsWith)
    {
        if (serviceCollection == null)
        {
            throw new ArgumentNullException("serviceCollection");
        }
        ServiceLifetime serviceLifetime = ServiceLifetime.Scoped;
        serviceLifetime = typeof(T).Name switch
        {
            "TransientServiceAttribute" => ServiceLifetime.Transient,
            "ScopedServiceAttribute" => ServiceLifetime.Scoped,
            "SingletonServiceAttribute" => ServiceLifetime.Singleton,
            _ => throw new ArgumentException("这个类型" + typeof(T).Name + " 在这个上下文中是非法的"),
        };
        if (!_loadedAssemblies.Any())
        {
            LoadAssemblies(scanAssembliesStartsWith);
        }

        List<Type> list = (from type in _loadedAssemblies.SelectMany((Assembly assembly) => assembly.GetTypes())
                           where type.IsDefined(typeof(T), inherit: false)
                           select type).ToList();
        foreach (Type serviceType in list)
        {
            List<Type> list2 = new List<Type>();
            list2 = ((!serviceType.IsGenericType || !serviceType.IsGenericTypeDefinition) ? (from type in _loadedAssemblies.SelectMany((Assembly a) => a.GetTypes())
                                                                                             where serviceType.IsAssignableFrom(type) && type.IsClass
                                                                                             select type).ToList() : (from type in _loadedAssemblies.SelectMany((Assembly a) => a.GetTypes())
                                                                                                                      where type.IsGenericType && type.IsClass && type.GetInterfaces().Any((Type i) => i.IsGenericType && i.GetGenericTypeDefinition() == serviceType.GetGenericTypeDefinition())
                                                                                                                      select type).ToList());
            if (list2.Any())
            {
                foreach (Type implementation in list2)
                {
                    bool flag = implementation.IsGenericType && implementation.IsGenericTypeDefinition;
                    Type service = ((flag && serviceType.IsGenericType && !serviceType.IsGenericTypeDefinition && serviceType.ContainsGenericParameters) ? serviceType.GetGenericTypeDefinition() : serviceType);
                    if (!serviceCollection.Any((ServiceDescriptor s) => s.ServiceType == service && s.ImplementationType == implementation))
                    {
                        serviceCollection.Add(new ServiceDescriptor(service, implementation, serviceLifetime));
                    }
                }
            }
            else if (serviceType.IsClass && !serviceCollection.Any((ServiceDescriptor s) => s.ServiceType == serviceType && s.ImplementationType == serviceType))
            {
                serviceCollection.Add(new ServiceDescriptor(serviceType, serviceType, serviceLifetime));
            }
        }
    }

    private static void LoadAssemblies(params string[] scanAssembliesStartsWith)
    {
        List<Assembly> list = new List<Assembly>();
        List<string> list2 = new List<string>();
        string baseDirectory = AppDomain.CurrentDomain.BaseDirectory;
        if (scanAssembliesStartsWith?.Any() ?? false)
        {
            if (scanAssembliesStartsWith.Length == 1)
            {
                string searchPattern = scanAssembliesStartsWith.First() + "*.dll";
                string[] files = Directory.GetFiles(baseDirectory, searchPattern);
                list2.AddRange(files);
            }
            if (scanAssembliesStartsWith.Length > 1)
            {
                foreach (string text in scanAssembliesStartsWith)
                {
                    string searchPattern2 = text + "*.dll";
                    string[] files2 = Directory.GetFiles(baseDirectory, searchPattern2);
                    list2.AddRange(files2);
                }
            }
        }
        else
        {
            string[] files3 = Directory.GetFiles(baseDirectory, "*.dll");
            list2.AddRange(files3);
        }



        foreach (string item2 in list2)
        {
            try
            {
                Assembly item = Assembly.LoadFrom(item2);
                list.Add(item);
            }
            catch (Exception)
            {
            }
        }
        _loadedAssemblies = list;
    }


}

